using System;
using System.Collections.Generic;


namespace TrueCode.DependencyManager
{
  public class Container : IContainer
  {
    private readonly BuildActionCollection _buildActions = new BuildActionCollection();
    private readonly List< object > _actionsSequence = new List< object >();
    private readonly ServiceCollection _services = new ServiceCollection();

    public Container( params object[] buildActionTypes ) : this( null, buildActionTypes )
    {
    }

    public Container( Container parentContainer, params object[] buildActionTypes )
    {
      ParentContainer = parentContainer;

      foreach( var buildActionType in buildActionTypes )
      {
        if( buildActionType == null )
          throw new ArgumentNullException( "buildActionTypes" );
        _actionsSequence.Add( buildActionType );
      }
    }

    public Container ParentContainer { get; set; }

    public BuildActionCollection Actions
    {
      get { return _buildActions; }
    }

    public ServiceCollection Services
    {
      get { return _services; }
    }

    public T Resolve< T >( object setting, BuildActionCollection sessionalBuildActions,
                           ServiceCollection sessionalServices )
    {
      return BuildUp( default( T ), setting, sessionalBuildActions, sessionalServices );
    }

    public T BuildUp< T >( T instance, object setting, BuildActionCollection sessionalBuildActions,
                           ServiceCollection sessionalServices )
    {
      return ( T )BuildUp( typeof( T ), instance, setting, sessionalBuildActions, sessionalServices );
    }

    public object BuildUp( Type aimType, object instance, object setting, BuildActionCollection sessionalBuildActions,
                           ServiceCollection sessionalServices )
    {
      var context = new BuildSession( new SessionAim( aimType, setting ), _actionsSequence, _buildActions,
                                      sessionalBuildActions, _services, sessionalServices, ParentContainer )
                      {Instance = instance};
      return context.Build();
    }

    #region Resolve overloads
    public T Resolve< T >()
    {
      return Resolve< T >( null, null );
    }

    public T Resolve< T >( object setting )
    {
      return Resolve< T >( setting, ( BuildActionCollection )null );
    }

    public T Resolve< T >( ServiceCollection sessionalServices )
    {
      return Resolve< T >( ( object )null, sessionalServices );
    }

    public T Resolve< T >( BuildActionCollection sessionalBuildActions )
    {
      return Resolve< T >( null, sessionalBuildActions );
    }

    public T Resolve< T >( object setting, BuildActionCollection sessionalBuildActions )
    {
      return Resolve< T >( setting, sessionalBuildActions, null );
    }

    public T Resolve< T >( object setting, ServiceCollection sessionalServices )
    {
      return Resolve< T >( setting, null, sessionalServices );
    }

    public T Resolve< T >( BuildActionCollection sessionalBuildActions, ServiceCollection sessionalServices )
    {
      return Resolve< T >( null, sessionalBuildActions, sessionalServices );
    }

    public object Resolve(Type type, object setting, BuildActionCollection sessionalBuildActions, ServiceCollection sessionalServices)
    {
      return BuildUp( type, null, setting, sessionalBuildActions, sessionalServices );
    }
    #endregion

    #region BuildUp overloads
    public T BuildUp< T >( T instance )
    {
      return BuildUp( instance, ( BuildActionCollection )null );
    }

    public T BuildUp< T >( T instance, object settings )
    {
      return BuildUp( instance, settings, ( BuildActionCollection )null );
    }

    public T BuildUp< T >( T instance, ServiceCollection sessionalServices )
    {
      return BuildUp( instance, null, sessionalServices );
    }

    public T BuildUp< T >( T instance, BuildActionCollection sessionalBuildActions )
    {
      return BuildUp( instance, null, sessionalBuildActions );
    }

    public T BuildUp< T >( T instance, object setting, BuildActionCollection sessionalBuildActions )
    {
      return BuildUp( instance, setting, sessionalBuildActions, null );
    }

    public T BuildUp< T >( T instance, object setting, ServiceCollection sessionalServices )
    {
      return BuildUp( instance, setting, null, sessionalServices );
    }
    #endregion
  }
}